/* Includes ------------------------------------------------------------------*/
#include <main.h>

/* Private define-------------------------------------------------------------*/
#define CMD_IDLE        0     //空闲、待机模式，无IAP操作
#define CMD_READ        1     //IAP字节读命令
#define CMD_PROGRAM     2     //IAP字节编程命令
#define CMD_ERASE       3     //IAP扇区擦除命令
#define ENABLE_IAP      0x83  //使能IAP，设置CPU等待时间
/* Private variables----------------------------------------------------------*/
static uint8_t IapReadByte(uint16_t addr);
static void IapProgramByte(uint16_t addr,uint8_t dat);
static void IapEraseSector(uint16_t addr);
/* Public variables-----------------------------------------------------------*/
IAP_t IAP = 
{
  FALSE,
  0,
  IapReadByte,
  IapProgramByte,
  IapEraseSector
};
/* Private function prototypes------------------------------------------------*/

/*
* @name   IapIdle
* @brief  关闭IAP
* @param  None
* @retval None   
*/
static void IapIdle()
{
  IAP_CONTR = 0;            //关闭IAP功能
  IAP_CMD   = CMD_IDLE;     //清除命令寄存器，MS1和MS0为0，待机模式，无ISP操作
  IAP_TRIG  = 0;            //清除触发寄存器
  IAP_ADDRH = 0xFF;         //将地址设置到非IAP地区
  IAP_ADDRL = 0xFF;
}

/*
* @name   IapReadByte
* @brief  读取一个字节
* @param  addr：要读取字节的地址
* @retval uint8_t：返回读到的字节数据
*/
static uint8_t IapReadByte(uint16_t addr)
{
  uint8_t dat;
  IAP_CONTR = ENABLE_IAP;       //使能IAP，最高位IAPEN置1，并设置CPU等待时间
  IAP_CMD   = CMD_READ;         //设置IAP命令，对EEPROM区进行字节读
  IAP_ADDRL = addr;             //设置IAP读取的低地址，IAP_ADDRL只会存储addr的低8位
  IAP_ADDRH = addr >> 8;        //设置IAP读取的高地址，将addr右移8位，则将低8位全部移出去了，剩下了高8位，赋给IAP_ADDRH
  IAP_TRIG  = 0x5a;             //按数据手册说法要写触发命令
  IAP_TRIG  = 0xa5;
  _nop_();                      //等待操作完成
  dat = IAP_DATA;               //读数据
  IapIdle();                    //关闭IAP功能，该函数可以不调用，只是出于安全考虑而使用，后面函数同理
  return dat;                   //返回读取到的数据
}
/*
* @name   IapProgramByte
* @brief  写入一个字节
* @param  addr：要被写入的地址
* @param  dat：写入的数据
* @retval None   
*/
static void IapProgramByte(uint16_t addr,uint8_t dat)
{
  IAP_CONTR = ENABLE_IAP;       //使能IAP，最高位IAPEN置1，并设置CPU等待时间
  IAP_CMD   = CMD_PROGRAM;      //设置IAP命令，对EEPROM区进行字节编程
  IAP_ADDRL = addr;             //设置IAP写入的低地址
  IAP_ADDRH = addr >> 8;        //设置IAP写入到高地址
  IAP_DATA  = dat;              //写入数据
  IAP_TRIG  = 0x5a;             //写触发命令
  IAP_TRIG  = 0xa5;
  _nop_();                      //等待操作完成
  IapIdle();                    //关闭IAP功能
}
/*
* @name   IapEraseSector
* @brief  扇区擦除（每扇区为512字节）
* @param  addr：要擦除的扇区地址
* @retval None   
*/
static void IapEraseSector(uint16_t addr)
{
  IAP_CONTR = ENABLE_IAP;       //使能IAP，最高位IAPEN置1，并设置CPU等待时间
  IAP_CMD   = CMD_ERASE;        //设置IAP命令，对EEPROM区进行扇区擦除
  IAP_ADDRL = addr;             //设置IAP擦除扇区的低地址
  IAP_ADDRH = addr >> 8;        //设置IAP擦除扇区的高地址
  IAP_TRIG  = 0x5a;             //写触发命令
  IAP_TRIG  = 0xa5;         
  _nop_();                      //等待操作完成
  IapIdle();                    //关闭IAP功能
}

/********************************************************
  End Of File
********************************************************/